package com.feature50.makeover;

import com.feature50.makeover.ui.CandylandScrollbarUI;
import com.feature50.makeover.utils.FontResolver;
import com.feature50.makeover.utils.PaintUtils;
import com.feature50.makeover.utils.Platform;
import com.jgoodies.forms.layout.CellConstraints;
import com.jgoodies.forms.layout.FormLayout;

import javax.swing.*;
import javax.swing.event.ListDataEvent;
import javax.swing.event.ListDataListener;
import java.awt.*;
import java.awt.event.*;
import java.awt.geom.Point2D;

public class NavigationBottomPanel extends JPanel {
    private static CellConstraints CC = new CellConstraints();
    private JList recentList;
    private DefaultListModel recentModel;
    private DesktopFrame frame;
    private NavigationPanel navPanel;
    private FavoritesListModel favoritesModel;
    private JList favoritesList;

    public NavigationBottomPanel(DesktopFrame frame, NavigationPanel navPanel) {
        this.frame = frame;
        this.navPanel = navPanel;
        init();
    }

    private void init() {
        FormLayout layout = new FormLayout("fill:default:grow, fill:default:grow", "default, fill:default:grow");
        setLayout(layout);

        layout.setColumnGroups(new int[][] { new int[] { 1, 2 } });

        JToggleButton b1 = new GlossButton("My Favorites");
        JToggleButton b2 = new GlossButton("Recent");
        ButtonGroup g = new ButtonGroup();
        g.add(b1);
        g.add(b2);
        b1.setSelected(true);

        add(b1, CC.xy(1, 1));
        add(b2, CC.xy(2, 1));
//        add(b2, CC.xyw(1, 1, 2));
//        b2.setEnabled(false);

        final JPanel cardPanel = new JPanel();
        cardPanel.setOpaque(false);
        add(cardPanel, CC.xyw(1, 2, 2));
        cardPanel.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10));

        final CardLayout cardLayout = new CardLayout();
        cardPanel.setLayout(cardLayout);

        favoritesList = decorateList(new JList());
        favoritesModel = new FavoritesListModel();
        favoritesList.setModel(favoritesModel);
        JScrollPane favoritePane = decorateScrollPane(new JScrollPane(favoritesList));
        cardPanel.add(favoritePane, "favorites");

        recentList = decorateList(new JList());
        recentModel = new DefaultListModel();
        recentList.setModel(recentModel);
        JScrollPane recentPane = decorateScrollPane(new JScrollPane(recentList));
        cardPanel.add(recentPane, "recent");

        favoritesModel.addListDataListener(new ListDataListener() {
            public void intervalAdded(ListDataEvent e) {
                recentList.repaint();
            }

            public void intervalRemoved(ListDataEvent e) {
                recentList.repaint();

            }

            public void contentsChanged(ListDataEvent e) {
                recentList.repaint();
            }
        });

        b1.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                cardLayout.show(cardPanel, "favorites");
            }
        });

        b2.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                cardLayout.show(cardPanel, "recent");
            }
        });

        cardLayout.show(cardPanel, "favorites");

        recentList.addMouseListener(new MouseAdapter() {
            int oldSelection;

            public void mousePressed(MouseEvent e) {
                oldSelection = recentList.getSelectedIndex();
            }

            public void mouseClicked(MouseEvent e) {
                if ((oldSelection == recentList.getSelectedIndex()) && (e.getClickCount() == 2)) {
                    ENode app = (ENode) recentList.getSelectedValue();
                    frame.launchNavApp(app);
                }
            }
        });
    }

    private JList decorateList(JList list) {
        list.setOpaque(false);
        list.setFixedCellHeight(19);
        list.setFont(FontResolver.getFont(NavigationPanel.FONT_NAV_DEFAULT));
        list.setCellRenderer(new ListCellRenderer() {
            JPanel panel;
            JLabel label;
            JLabel starLabel;

            public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
                if (panel == null) {
                    panel = new JPanel();
                    panel.setBorder(BorderFactory.createEmptyBorder(2, 2, 2, 2));
                    panel.setLayout(new FormLayout("fill:default:grow, " + NavigationPanel.STAR_NORMAL.getWidth() + "px, 5px", "default"));

                    label = new JLabel();
                    panel.add(label, new CellConstraints().xy(1, 1));
                    label.setFont(list.getFont());

                    starLabel = new JLabel();
                    panel.add(starLabel, new CellConstraints().xy(2, 1));
                }

                ENode app = (ENode) value;
                label.setIcon(frame.getNodeIcon(app));
                label.setText(app.getDisplay());

                if (isSelected) {
                    label.setForeground(Color.BLACK);
                    panel.setBackground(new Color(202, 202, 202));
                    panel.setOpaque(true);
                } else {
                    label.setForeground(Color.WHITE);
                    if (index % 2 == 0) {
                        panel.setBackground(new Color(255, 255, 255, 32));
                        panel.setOpaque(true);
                    } else {
                        panel.setOpaque(false);
                    }
                }

                if (navPanel.isFavorite(app)) {
                    starLabel.setIcon(new ImageIcon(NavigationPanel.STAR_MARKED));
                } else if (isHoverNode(list, app)) {
                    starLabel.setIcon(new ImageIcon((isSelected) ? NavigationPanel.STAR_SELECTED : NavigationPanel.STAR_NORMAL));
                } else {
                    starLabel.setIcon(null);
                }

                return panel;
            }
        });

        NavigationBottomPanel.addHoverNodeListeners(navPanel, list);

        return list;
    }

    static void addHoverNodeListeners(final NavigationPanel navPanel, final JList list) {
        list.addMouseMotionListener(new MouseMotionAdapter() {
            public void mouseMoved(MouseEvent e) {
                if (navPanel.getBuilt() != 1f) return;

                Object node = null;
                Object oldNode = list.getClientProperty("hoverNode");

                int row = list.locationToIndex(e.getPoint());

                // the list's proximity detection is quite liberal; double-check
                if (row != -1) {
                    Rectangle rect = list.getCellBounds(row, row);
                    if (!(rect.contains(e.getPoint()))) row = -1;
                }

                if (row != -1) node = list.getModel().getElementAt(row);

                if (node != oldNode) {
                    list.putClientProperty("hoverNode", node);
                    list.repaint();
                }
            }
        });

        list.addMouseListener(new MouseAdapter() {
            public void mouseClicked(MouseEvent e) {
                int starwidth = NavigationPanel.STAR_NORMAL.getWidth();
                int starx = list.getWidth() - starwidth - 5;

                if ((e.getX() >= starx) && (e.getX() <= (starx + starwidth))) {
                    int row = list.locationToIndex(e.getPoint());
                    if (row == -1) return;

                    ENode user = (ENode) list.getModel().getElementAt(row);
                    if (navPanel.isFavorite(user)) {
                        navPanel.removeFavorite(user);
                    } else {
                        navPanel.addFavorite(user);
                    }
                    list.repaint();
                }
            }

            public void mouseExited(MouseEvent e) {
                Object oldNode = list.getClientProperty("hoverNode");
                list.putClientProperty("hoverNode", null);
                if (oldNode != null) list.repaint();
            }
        });
    }

    private boolean isHoverNode(JList list, ENode app) {
        Object node = list.getClientProperty("hoverNode");
        if (node == null) return false;
        if (node == app) return true;
        return false;
    }

    private JScrollPane decorateScrollPane(JScrollPane pane) {
        pane.setOpaque(false);
        pane.getViewport().setOpaque(false);
        pane.setBorder(null);
        pane.getVerticalScrollBar().setUI(new CandylandScrollbarUI());
        pane.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
        return pane;
    }

    protected void paintComponent(Graphics g) {
        PaintUtils.paintGradient(
                (Graphics2D) g,
                new Point2D.Double(0, 0),
                new Point2D.Double(0, 1),
                new Point(0, 0),
                new Dimension(getWidth(), getHeight()),
                new Color[] { Color.BLACK, new Color(33, 35, 42) },
                null
        );
    }

    private class GlossButton extends JToggleButton {
        public GlossButton(String text) {
            super(text);
            init();
        }

        private void init() {
            setFocusable(false);
            setBorderPainted(false);
            setFocusPainted(false);
            setBorder(BorderFactory.createEmptyBorder(7, 0, 7, 0));
            setFont(FontResolver.getFont(NavigationPanel.FONT_NAV_HEADER));
        }

        protected void paintComponent(Graphics g) {
            Graphics2D g2d = (Graphics2D) g.create();

            PaintUtils.paintCandylandBackground(g2d, getHeight(), getWidth(), false);

            if (isSelected()) {
                g2d.setColor(new Color(255, 255, 255, 32));
                g2d.fillRect(0, 0, getWidth(), getHeight());
            }

            g2d.setColor(Color.WHITE);
            Platform.setAntialiasing(g2d, getFont());
            g2d.setFont(getFont());
            int ascent = g2d.getFontMetrics().getAscent();
            int width = (int) g2d.getFontMetrics().getStringBounds(getText(), g2d).getWidth();

            int x = (getWidth() / 2) - (width / 2);
            int y = (getHeight() / 2) + (ascent / 2);

            g2d.drawString(getText(), x, y);

            g2d.dispose();
        }
    }

    public void addRecentApp(ENode node) {
        int index = recentModel.indexOf(node);
        if (index == -1) {
            recentModel.add(0, node);
        } else {
            recentModel.removeElementAt(index);
            recentModel.add(0, node);
        }
    }

    public FavoritesListModel getFavoritesModel() {
        return favoritesModel;
    }
}